package com.hmall.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import co.elastic.clients.json.JsonData;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.domain.PageDTO;
import com.hmall.search.domain.dto.ItemDTO;
import com.hmall.search.domain.po.Item;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.mapper.ItemMapper;
import com.hmall.search.service.IItemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author 虎哥
 */
@Service
@Slf4j
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {

    private static  final String INDEX_NAME = "items";

    private static final String SUGGEST_NAME = "suggestion_suggest";

    private static final String SUGGEST_FIELD = "suggestion";

    @Autowired
    private ElasticsearchClient esClient;

    @Override
    public PageDTO<ItemDTO> esSearch(ItemPageQuery query){
        String brand = query.getBrand();
        String category = query.getCategory();
        String key = query.getKey();
        Integer maxPrice = query.getMaxPrice();
        Integer minPrice = query.getMinPrice();
        Integer pageNo = query.getPageNo();
        Integer pageSize = query.getPageSize();
        //es不会自动进行空值判断，需要手动处理
        SearchRequest.Builder requestBuilder = new SearchRequest.Builder()
                .index(INDEX_NAME)
                .from(pageSize * (pageNo - 1))
                .size(pageSize);

        requestBuilder.query(q -> q.bool(b -> {
            // 添加名称匹配查询（如果key不为空）
            if (StrUtil.isNotBlank(key)) {
                b.must(m -> m.match(ma -> ma.field("name").query(key)));
            } else {
                // 如果没有关键词，匹配所有文档
                b.must(m -> m.matchAll(ma -> ma));
            }

            // 添加品牌过滤条件（如果brand不为空）
            if (StrUtil.isNotBlank(brand)) {
                b.filter(fi -> fi.term(te1 -> te1.field("brand").value(brand)));
            }

            // 添加分类过滤条件（如果category不为空）
            if (StrUtil.isNotBlank(category)) {
                b.filter(fi -> fi.term(te2 -> te2.field("category").value(category)));
            }

            // 添加价格范围过滤条件（如果最大价格或最小价格不为空）
            if (maxPrice != null || minPrice != null) {
                co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery.Builder rangeBuilder =
                        new co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery.Builder().field("price");
                if (maxPrice != null) {
                    rangeBuilder.lte(JsonData.of(maxPrice));
                }
                if (minPrice != null) {
                    rangeBuilder.gte(JsonData.of(minPrice));
                }
                b.filter(fi -> fi.range(rangeBuilder.build()));
            }

            return b;
        }));

        SearchRequest request = requestBuilder.build();
        PageDTO<ItemDTO> pageDTO = new PageDTO<>();
        try {
            SearchResponse<ItemDoc> response = esClient.search(request, ItemDoc.class);
            HitsMetadata<ItemDoc> hits = response.hits();
            if (hits.total() == null || hits.total().value() == 0){
                return null;
            }
            //总数
            pageDTO.setTotal(hits.total().value());
            List<ItemDTO> itemDTOList = hits.hits().stream().map(hit -> {
                ItemDoc itemDoc = hit.source();
                ItemDTO itemDTO = BeanUtil.copyProperties(itemDoc, ItemDTO.class);
                assert itemDoc != null;
                itemDTO.setId(Long.valueOf(itemDoc.getId()));
                ItemDoc.Spec spec = itemDoc.getAttr_list().get(0);
                itemDTO.setSpec(spec.getValue());
                return itemDTO;
            }).collect(Collectors.toList());
            //商品集合
            pageDTO.setList(itemDTOList);
            //总页数
            pageDTO.setPages(hits.total().value()/pageSize+1);
        } catch (IOException e) {
            log.error("搜索异常 -> IOException，{}", e.getMessage());
        }
        return pageDTO;
    }


    /**
     * 自动补全
     * @param key
     * @return
     */
    @Override
    public List<String> suggestion(String key) throws IOException {
        SearchRequest request = new SearchRequest.Builder().index(INDEX_NAME).suggest(sg -> sg.text(key).suggesters(SUGGEST_NAME, sug -> sug.completion(
                comp -> comp.field(SUGGEST_FIELD).size(10).skipDuplicates(true)
        ))).build();
        SearchResponse<ItemDoc> response = esClient.search(request, ItemDoc.class);
        Suggestion<ItemDoc> itemDocSuggestion = response.suggest().get(SUGGEST_NAME).get(0);
        List<String> suggestions = itemDocSuggestion.completion().options().stream().map(CompletionSuggestOption::text).collect(Collectors.toList());
        log.warn("自动补全结果：{}", suggestions);
        return suggestions;
    }
}
